#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
using namespace std;
using namespace __gnu_pbds;
const long long MOD  = 1000000007LL;
const long long MOD2 = 1012455881LL;
const long long MOD3 = 930446593LL;
const long long INF = 1e16;
const int INT_INF   = 1e8;
typedef tree<pair<int,int>, null_type, less<pair<int,int>>, rb_tree_tag,tree_order_statistics_node_update> ordered_set;
int GCD(int a, int b){return b == 0 ? a : GCD(b, a % b);}
long long fast_exp(long long base, long long exp, long long mod = MOD, long long tot = 1) {
    for(;exp > 0; exp >>= 1, base = base * base % mod) if((exp & 1) == 1) tot = tot * base % mod;
    return tot;
}
long long slow_mult(long long base, long long exp, long long mod = MOD, long long tot = 0) {
    for(;exp > 0; exp >>= 1, base = base * 2 % mod) if((exp & 1) == 1) tot = (tot + base) % mod;
    return tot;
}
struct chash {
    static uint64_t splitmix64(uint64_t x) {x += 0x8e3779b97f4a7c15; x = (x ^ (x >> 30)) * 0xbf54876d1ce4e5b9; x = (x ^ (x >> 27)) * 0x94d049bb133111eb; return x ^ (x >> 31);}
    size_t operator()(uint64_t x) const { static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x + FIXED_RANDOM);}
    size_t operator()(pair<uint64_t,uint64_t> x) const { static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); return splitmix64(x.first + FIXED_RANDOM)^(splitmix64(x.second + FIXED_RANDOM) >> 1);}
};

//int f[100005],done[100005];
bitset<22> grid[22];
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
int bfs(int x, int y){
    int ans = 0;
    bitset<22> vis[22];
    for(int i = 0; i < 22; ++i) vis[i].reset();
    queue<vector<int>> q;
    vis[x][y]=1;
    q.push({x, y, 0});
    while(!q.empty()){
        int x=q.front()[0], y=q.front()[1], m=q.front()[2]; q.pop();
        ans=max(ans,m);
        for(int i = 0; i < 4; ++i){
            if(!grid[dx[i]+x][dy[i]+y])continue;
            if(vis[dx[i]+x][dy[i]+y])continue;
            vis[dx[i]+x][dy[i]+y]=1;
            q.push({dx[i]+x,dy[i]+y,m+1});
        }
    }
    return ans;
}

int main(){

    cin.sync_with_stdio(0); cin.tie(0); cout.tie(0);

    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);

    //char c; cin >> c;
    //cout << (char) (c+1) << endl;

    /*int n, k, m; cin >> n >> k >> m;
    m *= n;
    for(int a, b = 1; b < n; ++b){cin >> a; m -= a;}
    m=max(0,m);
    if(m>k)cout<<"-1\n";
    else cout<<m<<"\n";*/

    /*string s;int n,m;cin>>n>>m;
    int cor=0,pen=0;
    for(int a,i=0;i<m;++i){
        cin>>a>>s;
        if(s=="AC"&&!done[a]){++cor;done[a]=1;pen+=f[a];}
        else if(s=="WA") ++f[a];
    }
    cout << cor << " " << pen << "\n";*/

    char c;
    int h,w;cin>>h>>w;
    for(int i=1;i<=h;++i){
        for(int j=1;j<=w;++j){
            cin>>c;grid[i][j]=c=='.';
        }
    }

    int best = 0;
    for(int i = 1; i <= h; ++i)
        for(int j = 1; j <= w; ++j)
            best = max(best, bfs(i,j));
    cout<<best<<"\n";


    return 0;

}
